package com.lz.job;

import java.lang.reflect.Method;
import java.util.Map;

import org.springframework.aop.support.AopUtils;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.lz.job.log.LogDecorator;
import com.lz.job.resources.Constants;
import com.lz.job.sterotype.Job;

import sos.spooler.Job_impl;
import sos.spooler.Log;

/**
 * Job启动类.
 * <p>
 * <strong>所有日志请用英文书写，中文会导致任务无法执行.</strong>
 *
 * @author zhaoshb
 * @since 0.0.1
 */
public class JobStarter extends Job_impl {

	private static final String CONFIG_LOCATION = "classpath:spring/*.xml";

	private ClassPathXmlApplicationContext applicationContext = null;

	private Object bean = null;

	@Override
	public boolean spooler_init() throws Exception {
		this.initEnv();
		this.initJob();

		return true;
	}

	@Override
	public void spooler_exit() throws Exception {
		this.getLogger().info(this.getLogInfo("exit"));
	}

	@Override
	public boolean spooler_open() throws Exception {
		this.getLogger().info(this.getLogInfo("open"));

		return true;
	}

	@Override
	public void spooler_close() throws Exception {
		this.getApplicationContext().close();
		this.getLogger().info(this.getLogInfo("close"));
	}

	@Override
	public boolean spooler_process() throws Exception {
		this.invokeMethod();

		return false;
	}

	private void invokeMethod() throws Exception {
		try {
			Method method = this.getBean().getClass().getMethod(this.getStartMethodName(), new Class<?>[0]);
			method.invoke(this.getBean(), new Object[] {});
		} catch (Exception e) {
			this.getLogger().error(this.getLogInfo("invoke method failed."));
			throw e;
		}
	}

	private void initEnv() {
		JobEnv.logger = new LogDecorator(this.getLogger());
	}

	private void initJob() throws Exception {
		this.initApplicationContext();
		this.initJobConfiguration();
	}

	private void initJobConfiguration() throws Exception {
		Map<String, Object> beanMap = this.getApplicationContext().getBeansWithAnnotation(Job.class);
		if ((beanMap == null) || beanMap.isEmpty()) {
			throw new Exception("The bean with Job annotation doesn't exist.");
		}
		if (beanMap.size() > 1) {
			throw new Exception("Multi bean with Job annotation has been found.");
		}
		this.bean = beanMap.entrySet().iterator().next().getValue();

		Job jobAnnotation = AopUtils.getTargetClass(this.getBean()).getAnnotation(Job.class);
		JobEnv.JobName = jobAnnotation.name();
		JobEnv.startMethodName = jobAnnotation.method();
	}

	private void initApplicationContext() {
		this.applicationContext = new ClassPathXmlApplicationContext(JobStarter.CONFIG_LOCATION);
	}

	private String getLogInfo(String msg) {
		return this.getJobName() + Constants.COLON + msg;
	}

	private String getJobName() {
		return JobEnv.JobName;

	}

	private String getStartMethodName() {
		return JobEnv.startMethodName;
	}

	private Object getBean() {
		return this.bean;
	}

	private Log getLogger() {
		return this.spooler_log;
	}

	private ClassPathXmlApplicationContext getApplicationContext() {
		return this.applicationContext;
	}

}
